package wallet

import (
	"ChainCodeProject/tools"
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"encoding/gob"
	"errors"
	"github.com/boltdb/bolt"
)

/**
 * @author: 清秋
 * @email: 15770670622
 * @datetime: 22:27 2022/6/3
 * @Description:
 */

const PRIVATE_BUCKET = "private_bucket"

//为了封装一些方法
type Wallet struct {
	db *bolt.DB
}

func NewWallet(db *bolt.DB) (*Wallet, error) {
	//创建桶
	err := db.Update(func(tx *bolt.Tx) error {
		bk := tx.Bucket([]byte(PRIVATE_BUCKET))
		if bk == nil {
			_, err := tx.CreateBucket([]byte(PRIVATE_BUCKET))
			if err != nil {
				return err
			}
		}
		return nil
	})

	if err != nil {
		return nil, err
	}
	return &Wallet{db}, nil

}

//专门用来保存私钥的方法
func (w *Wallet) SavePrivateKey(pri *ecdsa.PrivateKey,addr string)error{
	db := w.db
	err := db.Update(func(tx *bolt.Tx) error {
		bk := tx.Bucket([]byte(PRIVATE_BUCKET))
		if bk == nil {
			return errors.New("桶不存在！")
		}

		//需要序列化，把pri转为[]byte
		priBytes, err := tools.Serialize(pri)
		if err != nil {
			return err
		}

		err = bk.Put([]byte(addr), priBytes)
		if err != nil {
			return err
		}
		return nil
	})
	return err
}

func (w *Wallet) NewAddress() (string, *ecdsa.PrivateKey, error) {
	//生成一个p256的一个曲线
	curve := elliptic.P256()

	pri, pub, err := NewPubKeys(curve)
	if err != nil {
		return "", nil, err
	}

	//进行转换 序列化把公钥转为字节切片类型[]bytes
	pub_bytes := elliptic.Marshal(curve, pub.X, pub.Y)

	//对公钥进行sha256计算
	pub_sha256 := tools.GetHash(pub_bytes)

	//对pub_sha256进行ripemd160计算 160位，20个字节
	pubhash := tools.Ripemd160(pub_sha256)

	//将版本号和pubhash拼接
	ver_pubhash := append([]byte{VERSION}, pubhash...)

	//进行sha256运算
	first_hash := tools.GetHash(ver_pubhash)
	second_hash := tools.GetHash(first_hash)
	check := second_hash[:4]

	//将ver_pubhash和check进行拼接
	ver_pubhash_check := append(ver_pubhash, check...)

	//将ver_pubhash_check进行base58转换
	addr := tools.Encode(ver_pubhash_check)

	return addr, pri, nil
}

//获取私钥
func (w *Wallet) ShowPrivateKey(addr string) (ecdsa.PrivateKey, error) {
	db := w.db
	var pri ecdsa.PrivateKey
	err := db.View(func(tx *bolt.Tx) error {
		bk := tx.Bucket([]byte(PRIVATE_BUCKET))
		if bk == nil {
			return nil
		}
		priByte := bk.Get([]byte(addr))

		de := gob.NewDecoder(bytes.NewBuffer(priByte))
		gob.Register(elliptic.P256())
		err := de.Decode(&pri)
		if err != nil {
			return err
		}
		return nil
	})
	return pri, err
}

func (w *Wallet) CheckAddr(addr string) bool {
	//1,进行解密
	ver_pubhash_check := tools.Decode(addr)

	//2.对ver_pubhash_check进行截取
	check := ver_pubhash_check[len(ver_pubhash_check)-4:]
	ver_pubhash := ver_pubhash_check[:len(ver_pubhash_check)-4]

	//3.对ver_pubhash进行双sha256计算
	first_hash := tools.GetHash(ver_pubhash)
	second_hash := tools.GetHash(first_hash)

	//4.对second_hash进行截取前四位
	newCheck := second_hash[:4]

	//5.进行比较
	return bytes.Compare(check, newCheck) == 0

}
